require 'depac-common/log'
require 'fileutils'
require 'open3'

module Depac
  class Utils
    public
    def self.get_env_filename(buildlabel)
      return "depac-env-#{buildlabel}"
    end
    def self.run_if_not_exists(markerfile, process_name)
      if File.exists?(markerfile) then Log.info("Skipping #{process_name}..."); 
        return;
      else 
        yield
        FileUtils.touch(markerfile)
      end
    end
    
    def self.build_mcid(vm) 
        return vm['snaprole'].downcase
    end
    
    def self.logged_remoteExec(cmd, mcid, echo=true) 
      Log.info("Running: #{cmd} on #{mcid}") if echo
      return logged_exec(cmd, "[#{mcid}] ", false)
    end
    
    def self.logged_exec(cmd, prefix="", echo=true) 
      return logged_exec_new(cmd, prefix, echo)
    end
    
    def self.deleteEnvironmentForDocker(nodeInfoMap)
        typeArr = getEnvironmentTypes()
        private_key_path = Depac::CloudDeploymentConstants::CLD_DPL_KEYPATH
    
       typeArr.each do |type|
       if(nodeInfoMap[type] != nil)
        nodeInfoMap[type].each do |role, nodeInfoArr|

          Depac::Log.write("INFO", "Updating factory setup data #{type}:#{role}")
          Depac::Log.write("INFO", Depac::CloudDeploymentConstants::BORDER_LINE)
          
          nodeInfoArr.each do |hostnameIPMap|
              #1.clean docker container
              if hostnameIPMap['dockerID'] !=nil
		        cmdstr= "ssh -t -t -i #{private_key_path} root@#{hostnameIPMap['IP']} -o StrictHostKeyChecking=no 'sudo docker stop #{hostnameIPMap['dockerID']};sudo docker rm -f #{hostnameIPMap['dockerID']}'"
		        Depac::Log.write("INFO", "Executing command: #{cmdstr}")
		        output =  `#{cmdstr}`
		        Depac::Log.write("INFO", "Executing command output: #{output}")
		      end
          end
        end
      end
    end
   end
    
    private
    def self.logged_exec_old(cmd, prefix="", echo=true) 
      exitstatus=-1
      Log.info("Running: #{cmd}") if echo
      output=`#{cmd}`
      Log.info(output)
      if $? == 0; return nil; else return $?; end
    end
    
    def self.logged_exec_new(cmd, prefix="", echo=true) 
      exitstatus=-1
      Log.info("Running: #{cmd}") if echo
      Open3.popen2e(cmd) { |i, oe, t| 
        oe.each {|line| Log.info("#{prefix}#{line.strip}")}
        i.close; oe.close
        exitstatus = t.value.exitstatus
        puts "====== exitstaus: #{t.value.exitstatus} #{exitstatus}"
      }
      if exitstatus == 0; return nil; else return exitstatus; end
    end
    
    def self.ensureKeys(filepath, comment) 
      if (File.exists?(filepath) && File.exists?(filepath + ".pub"))
        return
      else 
        Log.info("Generating workstation keys")
        cmd=%Q^ ssh-keygen -t rsa -C #{comment} -f #{filepath} -N "" 2>&1 ; chmod 600 #{filepath} ^
        if Utils.logged_exec(cmd) then Log.fatal_exit("Error while generating #{comment} keys") end
      end
    end
    
    #launchRestAutomation only need build label appserverIP and extraInfo which contains autotestsever,restAutomationConfig,restAutomationDirectory,autotestcommand,restAutomationScript,restAutomationResult
    def self.launchRestAutomation(buildlabel, appserverIP, extraInfo) 
       Log.info("launchRestAutomation entry:buildlabel=#{buildlabel},appserverIP=#{appserverIP},extraInfo=#{extraInfo}")
       autoTestFinish=false

       cmd="ssh -oStrictHostKeyChecking=no -t -l root #{extraInfo['autotestsever']} \"bash --login -c 'cd /scripts;./restAutomatoinConfig.sh #{appserverIP} #{buildlabel}'\""
       Log.info("cmd_launchRestAT=#{cmd}")
       output =`#{cmd}`
       if $? == 0
          Log.info("Check Auto testing result on #{appserverIP}")
          commandGetResult="ssh -oStrictHostKeyChecking=no -t -l root #{extraInfo['autotestsever']} \"sudo cat #{extraInfo['restAutomationResult']}\""
          Log.info("commandGetResult=#{commandGetResult}")
          output = `#{commandGetResult}`       
           if output.rstrip == "true"
               autoTestFinish=true
           else
               puts "#{output.rstrip} is not equal with success"
           end
       else
          Log.info("#{output}")    
       end
       Log.info("launchRestAutomation exit:autoTestFinish=#{autoTestFinish}")
       return autoTestFinish
    end
    
    def self.getHostnames(build_label, env, type, role, no_of_nodes, existing_env_node_count)
	    hostnames = Array.new
	
	    no_of_nodes_i = no_of_nodes.to_i
	    Log.info("Utils.getHostnames: no_of_nodes_i : #{no_of_nodes_i}")
	    existing_env_node_count_i = existing_env_node_count.to_i
	    Log.info("Utils.getHostnames: existing_env_node_count_i : #{existing_env_node_count_i}")
	    
	    for i in 1..no_of_nodes_i
	      hostnameString = "#{build_label}-#{env}-#{type}-#{role}-#{i+existing_env_node_count_i}".downcase
	      Log.info("Utils.getHostnames: hostnameString: #{hostnameString}")
	      hostnames.push(hostnameString)
	    end
	    return hostnames
     end
     
     def self.updateConfigWithNodeInformation(configObject, nodeInfoMap)	
		  if(nodeInfoMap != nil)
			 nodeInfoMap.each do |role, nodeInfoArr|
				roleConfig = configObject.getNodeConfigurationByRole(role)
				
				#in cause user will specify each node info. if so , we need to do merge work 
				if roleConfig[Depac::CloudDeploymentConstants::NODE_INFO] == nil
				   roleConfig[Depac::CloudDeploymentConstants::NODE_INFO] = nodeInfoArr
				   Log.info("After merge, nodeInfo of #{role} is: #{roleConfig[Depac::CloudDeploymentConstants::NODE_INFO]}")
				else
				   Log.info("Start merge nodeInfo hash table...............................")
				   
	               i=0
				   
				   roleConfig[Depac::CloudDeploymentConstants::NODE_INFO].each do |nodeInfo|	
				   		
				   	    roleConfig[Depac::CloudDeploymentConstants::NODE_INFO][i]=nodeInfoArr[i].merge roleConfig[Depac::CloudDeploymentConstants::NODE_INFO][i] 
				        Log.info("After merge, nodeInfo[#{i}] is: #{roleConfig[Depac::CloudDeploymentConstants::NODE_INFO][i]}")   
				   		                              
                        i=i+1
				        
				   end
				   
				   if i < nodeInfoArr.size				   
				        for i in i...nodeInfoArr.size
				             roleConfig[Depac::CloudDeploymentConstants::NODE_INFO].push(nodeInfoArr[i])
				        end 				   
				   end
				end
			end
		  end
     end
    
     #build a metadata--nodeInfoMap
     def self.buildNodeInfoMap(envConfigObject)
        nodeInfoMap = Hash.new

       envConfigObject[:vms].each do |roleConfig|
             role= roleConfig[Depac::CloudDeploymentConstants::ROLE]         
             nodeInfoMap[role]=roleConfig[Depac::CloudDeploymentConstants::NODE_INFO] if roleConfig[Depac::CloudDeploymentConstants::NODE_INFO] != nil       
        end       
        return nodeInfoMap
     end 
    
    
    #build a metadata--nodeInfoMap by role
    def self.buildNodeInfoMapbyRole(envConfigObject,targetrole)
        nodeInfoMap = Hash.new

        envConfigObject.vms.each do |roleConfig|
             role= roleConfig[Depac::CloudDeploymentConstants::ROLE]       
             if role == targetrole
                nodeInfoMap[role]=roleConfig[Depac::CloudDeploymentConstants::NODE_INFO] if roleConfig[Depac::CloudDeploymentConstants::NODE_INFO] != nil 
                break
             end      
        end       
        return nodeInfoMap
    end 
    
    def self.getIPListbyRole(nodeInfoMap, role)  
          
           ipList=Array.new
         
           if nodeInfoMap !=nil
                  nodeInfoMap.each do |_role, nodeArr|
                        if _role == role
                             if nodeArr !=nil                               
                                  nodeArr.each do|node|
                                      ipList.push(node['IP']) if node['IP']
                                  end                              
                             end
                        end
                  end
           end 
           
           return ipList  
    end
     
    # Generate the output YAML file.
    def self.generateOutputYAML(outputConfig, fileName, path)
	   if(path == nil)
		   filePath = "#{File.expand_path("~/DeploymentOutput")}"
	   else
		   filePath = "#{File.expand_path(path)}"
	   end
	
	   FileUtils.mkdir_p "#{filePath}"
	
	   File.open("#{filePath}/#{fileName}.yml","w") {|f|
		  f.puts(outputConfig.to_yaml())
		  f.close
	   }
    end
         
  end
end